package com.cloudbroker.bcs.platform.ltb.middle.mybatis;

import com.cloudbroker.bcs.common.dao.base.CRUDTemplate;
import com.cloudbroker.bcs.common.dao.base.MyBatisPojo;
import com.cloudbroker.bcs.common.entity.Pageable;
import com.cloudbroker.bcs.platform.ltb.middle.entity.ViewpointMsg;
import org.apache.ibatis.builder.StaticSqlSource;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.result.DefaultResultContext;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.*;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Handler;

/**
 * Created by zhaosh19213 on 2016/9/13.
 */
@Intercepts({@Signature(type = Executor.class, method = "query", args = {
        MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class }),
        @Signature(type = Executor.class, method = "update", args = {
        MappedStatement.class, Object.class })})
public class BaseDBMethodInterceptor implements Interceptor,Serializable {
    /**
     * serialVersionUID.
     */
    private static final long serialVersionUID = 0l;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        Object parameterObject = invocation.getArgs()[1];
        BoundSql boundSql = mappedStatement.getBoundSql(parameterObject);
        List<ResultMap> resultMaps = mappedStatement.getResultMaps();
        if (mappedStatement.getId().contains("DAOBase")) {

            CRUDTemplate crudTemplate = new CRUDTemplate(parameterObject);
            String newsql = "";
            if (mappedStatement.getSqlCommandType().name().equals("SELECT")){
                newsql = crudTemplate.get();
            }else if(mappedStatement.getSqlCommandType().name().equals("INSERT")){
                newsql = crudTemplate.insert();
            }else if(mappedStatement.getSqlCommandType().name().equals("UPDATE")){
                newsql = crudTemplate.update();
            }else if(mappedStatement.getSqlCommandType().name().equals("DELETE")){
                newsql = crudTemplate.delete();
            }

            BoundSql newBoundSql = new BoundSql(
                    mappedStatement.getConfiguration(), newsql,
                    boundSql.getParameterMappings(),
                    parameterObject);
            StaticSqlSource sqlSource = new StaticSqlSource(mappedStatement.getConfiguration(),
                    newsql,boundSql.getParameterMappings());

            List<ResultMap> copyFromResultMaps = copyFromResultMap(resultMaps, mappedStatement.getConfiguration(),parameterObject.getClass());
            invocation.getArgs()[0] = copyFromMappedStatement(mappedStatement,new PaginationInterceptor.BoundSqlSqlSource(newBoundSql), copyFromResultMaps);
        }
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object o) {
        return Plugin.wrap(o, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }

    private MappedStatement copyFromMappedStatement(MappedStatement ms,SqlSource sqlSource,
                                                    List<ResultMap> resultMaps) {
        MappedStatement.Builder builder = new MappedStatement.Builder(
                ms.getConfiguration(), ms.getId(), sqlSource,
                ms.getSqlCommandType());
        if (ms.getKeyProperties() != null) {
            for (String keyProperty : ms.getKeyProperties()) {
                builder.keyProperty(keyProperty);
            }
        }
        builder.resource(ms.getResource());
        builder.fetchSize(ms.getFetchSize());
        builder.statementType(ms.getStatementType());
        builder.keyGenerator(ms.getKeyGenerator());
        builder.timeout(ms.getTimeout());
        builder.parameterMap(ms.getParameterMap());
        builder.resultMaps(resultMaps);
        builder.cache(ms.getCache());
        builder.resultSetType(ms.getResultSetType());
        return builder.build();
    }

    private List<ResultMap> copyFromResultMap(List<ResultMap> resultMaps,
                                              Configuration configuration, Class T){
        List<ResultMap> resultMapList = new ArrayList<>();
        for (ResultMap resultMap : resultMaps){
            ResultMap.Builder builder = new ResultMap.Builder(configuration,
                    resultMap.getId(),T,resultMap.getResultMappings());
            resultMap = builder.build();
            resultMapList.add(resultMap);
        }
        return resultMapList;
    }
}
